package com.mail.anteater.facade;

import java.util.ArrayList;
import java.util.Date;

import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

import com.mail.anteater.bean.Category;
import com.mail.anteater.bean.Filter;
import com.mail.anteater.bean.MailResponse;
import com.mail.anteater.bean.Order;
import com.mail.anteater.bean.Priority;
import com.mail.anteater.bean.Status;
import com.mail.anteater.bean.Type;
import com.mail.anteater.dao.MapperDAO;
import com.mail.anteater.dao.UserDAO;
import com.mail.anteater.hibernate.HibernateUtil;
import com.mail.anteater.hibernate.mapping.Inbox;
import com.mail.anteater.hibernate.mapping.InboxListing;
import com.mail.anteater.hibernate.mapping.Outbox;
import com.mail.anteater.hibernate.mapping.OutboxListing;
import com.mail.anteater.hibernate.mapping.TempInbox;
import com.mail.anteater.hibernate.mapping.TempInboxMapper;
import com.mail.anteater.hibernate.mapping.TempOutbox;
import com.mail.anteater.hibernate.mapping.TempOutboxMapper;
import com.mail.anteater.hibernate.mapping.User;
import com.mail.anteater.util.Func;

public class AntMailService implements MailService {

	final static Logger logger = Logger.getLogger(AntMailService.class);
	
	@Override
	public MailResponse deleteMail(String owner, Filter filter, Category category) {
		logger.debug("AntMailService.deleteMail() started");
		logger.debug("owner="+owner);
		logger.debug("filter="+filter.toString());
		logger.debug("category="+category.toString());
		MailResponse response = new MailResponse();
		if(category.equals(Category.INBOX)){
			for(Long s : filter.getIds()){
				String hqlDelete = "delete from Inbox where id=" + s + " and userId='" + owner + "'";
				HibernateUtil.customQuery(hqlDelete, false);
			}
			response.setStatus(true);
		}else if(category.equals(Category.OUTBOX)){
			for(Long s : filter.getIds()){
				String hqlDelete = "delete from Outbox where id=" + s + " and userId='" + owner + "'";
				HibernateUtil.customQuery(hqlDelete, false);
			}
			response.setStatus(true);
		}else{
			response.setStatus(false);
		}

		logger.debug("AntMailService.deleteMail() ended");
		return response;
	}

	@Override
	public MailResponse retrieveMail(String retriever, Filter filter, Category category) {
		logger.debug("AntMailService.retrieveMail() started");
		logger.debug("retriever="+retriever);
		logger.debug("filter="+filter.toString());
		logger.debug("category="+category.toString());
		MailResponse response = new MailResponse();

		if(category.equals(Category.INBOX)){
			
			User user = UserDAO.getUser(retriever, false);
			if(user == null){
				user = new User();
				user.setUserId(retriever);
				user.setRegisterAt(new Date());
				HibernateUtil.create(user, false);
			}
			TempInboxMapper tempInboxMapper = MapperDAO.isTempInboxAvailable(user.getUserId(), user.getLastInboxAt(), filter.toStringWithoutPage(), false); 
			if(tempInboxMapper != null){
				tempInboxMapper.setCreateDt(new Date());
				HibernateUtil.update(tempInboxMapper, false);
			}else{
				String sqlRemoveTempInboxMapper = "delete from TempInboxMapper where userId = '" + retriever + "'";
				HibernateUtil.customQuery(sqlRemoveTempInboxMapper, false);
				
				String sqlRemoveTempInbox = "delete from TempInbox where userId = '" + retriever + "'";
				HibernateUtil.customQuery(sqlRemoveTempInbox, false);
				
				DetachedCriteria cri = DetachedCriteria.forClass(InboxListing.class);
				cri.add(Restrictions.eq("userId", retriever));
				if(filter.getSubject() != null)
					cri.add(Restrictions.like("subject", filter.getSubject(), MatchMode.ANYWHERE));
				if(filter.getContent() != null)
					cri.add(Restrictions.like("content", filter.getContent(), MatchMode.ANYWHERE));
				if(filter.getPriority() != null)
					cri.add(Restrictions.eq("priority", filter.getPriority().toString()));
				if(filter.getType() != null)
					cri.add(Restrictions.eq("type", filter.getType().toString()));
				if(filter.getSender() != null)
					cri.add(Restrictions.eq("sender", filter.getSender()));
				if(filter.getReceiver() != null)
					cri.add(Restrictions.like("receivers", filter.getReceiver(), MatchMode.ANYWHERE));
				if(filter.getCc() != null)
					cri.add(Restrictions.like("cc", filter.getCc(), MatchMode.ANYWHERE));
				if(filter.getStatus() != null)
					cri.add(Restrictions.eq("status", filter.getStatus()));
				if(filter.getFrom() != null && filter.getTo() != null)
					cri.add(Restrictions.between("receiveDt", filter.getFrom(), filter.getTo()));
				
				ArrayList<Object> list = HibernateUtil.list(cri, false);
				if(list != null){
					if(list.size() > 0){
						TempInboxMapper mapper = new TempInboxMapper();
						mapper.setUserId(retriever);
						mapper.setCreateDt(new Date());
						mapper.setLastInboxAt(user.getLastInboxAt());
						mapper.setFilter(filter.toStringWithoutPage());
						HibernateUtil.create(mapper, false);
						
						for(Object o : list){
							TempInbox tempInbox = Func.castTempInbox((InboxListing) o);
							HibernateUtil.create(tempInbox, false);
						}
					}
				}
			}
			
			DetachedCriteria cri = DetachedCriteria.forClass(TempInbox.class);
			cri.add(Restrictions.eq("userId", retriever));
			if(filter.getSortBy() != null){
				if(filter.getOrder().equals(Order.ASC)){
					cri.addOrder(org.hibernate.criterion.Order.asc(filter.getSortBy().toString()));
				}else{
					cri.addOrder(org.hibernate.criterion.Order.desc(filter.getSortBy().toString()));	
				}
			}
			
			int startIndex = 0;
			if(filter.getRecordPerPage() != -1 && filter.getPage() != -1){
				if(filter.getPage() != 1){ //page 1
					startIndex = (filter.getPage()-1) * filter.getRecordPerPage();
				}
			}
			
			ArrayList<Object> list = HibernateUtil.list(cri, startIndex, filter.getRecordPerPage(), false);
			if(list != null){
				response.setInbox(new ArrayList<Inbox>());
				for(Object o : list){
					response.getInbox().add(Func.castInbox(((TempInbox) o)));
				}
				response.setStatus(true);
			}else{
				response.setStatus(false);
			}
		}else if(category.equals(Category.OUTBOX)){
			
			User user = UserDAO.getUser(retriever, false);
			if(user == null){
				user = new User();
				user.setUserId(retriever);
				user.setRegisterAt(new Date());
				HibernateUtil.create(user, false);
			}
			TempOutboxMapper tempOutboxMapper = MapperDAO.isTempOutboxAvailable(user.getUserId(), user.getLastOutboxAt(), filter.toStringWithoutPage(), false); 
			if(tempOutboxMapper != null){
				tempOutboxMapper.setCreateDt(new Date());
				HibernateUtil.update(tempOutboxMapper, false);
			}else{
				String sqlRemoveTempOutboxMapper = "delete from TempOutboxMapper where userId = '" + retriever + "'";
				HibernateUtil.customQuery(sqlRemoveTempOutboxMapper, false);
				
				String sqlRemoveTempOutbox = "delete from TempOutbox where userId = '" + retriever + "'";
				HibernateUtil.customQuery(sqlRemoveTempOutbox, false);
				
				DetachedCriteria cri = DetachedCriteria.forClass(OutboxListing.class);
				cri.add(Restrictions.eq("userId", retriever));
				
				if(filter.getContent() != null)
					cri.add(Restrictions.like("content", filter.getContent(), MatchMode.ANYWHERE));
				if(filter.getPriority() != null)
					cri.add(Restrictions.eq("priority", filter.getPriority().toString()));
				if(filter.getType() != null)
					cri.add(Restrictions.eq("type", filter.getType().toString()));
				if(filter.getSender() != null)
					cri.add(Restrictions.eq("sender", filter.getSender()));
				if(filter.getReceiver() != null)
					cri.add(Restrictions.like("receivers", filter.getReceiver(), MatchMode.ANYWHERE));
				if(filter.getCc() != null)
					cri.add(Restrictions.like("cc", filter.getCc(), MatchMode.ANYWHERE));
				if(filter.getStatus() != null)
					cri.add(Restrictions.eq("status", filter.getStatus()));
				if(filter.getFrom() != null && filter.getTo() != null)
					cri.add(Restrictions.between("sentDt", filter.getFrom(), filter.getTo()));
				
				ArrayList<Object> list = HibernateUtil.list(cri, false);
				if(list != null){
					if(list.size() > 0){
						TempOutboxMapper mapper = new TempOutboxMapper();
						mapper.setUserId(retriever);
						mapper.setCreateDt(new Date());
						mapper.setLastOutboxAt(user.getLastOutboxAt());
						mapper.setFilter(filter.toStringWithoutPage());
						HibernateUtil.create(mapper, false);
					
						for(Object o : list){
							TempOutbox tempOutbox = Func.castTempOutbox((OutboxListing) o);
							HibernateUtil.create(tempOutbox, false);
						}
					}
				}
			}
			
			DetachedCriteria cri = DetachedCriteria.forClass(TempOutbox.class);
			cri.add(Restrictions.eq("userId", retriever));		
			
			int startIndex = 0;
			if(filter.getRecordPerPage() != -1 && filter.getPage() != -1){
				if(filter.getPage() != 1){ //page 1
					startIndex = (filter.getPage()-1) * filter.getRecordPerPage();
				}
			}
			
			ArrayList<Object> list = HibernateUtil.list(cri, startIndex, filter.getRecordPerPage(), false);
			if(list != null){
				response.setOutbox(new ArrayList<Outbox>());
				for(Object o : list){
					response.getOutbox().add(Func.castOutbox(((TempOutbox) o)));
				}
				response.setStatus(true);
			}else{
				response.setStatus(false);
			}
		}else{
			response.setStatus(false);
		}

		logger.debug("AntMailService.retrieveMail() ended");
		return response;
	}

	@Override
	public MailResponse sendMail(String sender, ArrayList<String> receivers, ArrayList<String> cc, String subject, String contents, String instruction, Priority priority, Type type){
		logger.debug("AntMailService.sendMail() started");
		MailResponse response = new MailResponse();
		Date processDate = new Date();

		// first step is to make sure all parties involved is in user table
		User senderDao = new User();
		senderDao.setUserId(sender);
		senderDao.setLastOutboxAt(processDate);
		HibernateUtil.createOrUpdate(senderDao, false);

		Outbox outbox = new Outbox();
		outbox.setUserId(sender);
		outbox.setSubject(subject);
		outbox.setContent(contents);
		outbox.setInstruction(instruction);
		outbox.setType(type.toString());
		outbox.setPriority(priority.toString());
		outbox.setSentDt(processDate);
		if(receivers != null) outbox.setReceivers(Func.getDelimiteredNumber(receivers));
		if(cc != null) outbox.setCc(Func.getDelimiteredNumber(cc));
		
		HibernateUtil.create(outbox, false);
		
		ArrayList<String> allReceivers = new ArrayList<String>();
		allReceivers.addAll(receivers);
		allReceivers.addAll(cc);
		for(String s : allReceivers){
			User receiverDao = new User();
			receiverDao.setUserId(s);
			receiverDao.setLastInboxAt(processDate);
			HibernateUtil.createOrUpdate(receiverDao, false);
			
			Inbox inbox = new Inbox();
			inbox.setUserId(s);
			inbox.setSubject(subject);
			inbox.setContent(contents);	        
			inbox.setInstruction(instruction);
			inbox.setType(type.toString());
			inbox.setPriority(priority.toString());
			inbox.setSender(sender);
			inbox.setReceiveDt(processDate);
			inbox.setStatus(Status.UNREAD.toString());
			if(receivers != null) inbox.setReceivers(Func.getDelimiteredNumber(receivers));
			if(cc != null) inbox.setCc(Func.getDelimiteredNumber(cc));
			HibernateUtil.create(inbox, false);
		}
		response.setStatus(true);
		
		logger.debug("AntMailService.sendMail() ended");
		return response;
	}

	@Override
	public MailResponse readMail(String retriever, long id, Category category) {
		logger.debug("AntMailService.readMail() started");
		MailResponse response = new MailResponse();
		
		if(category.equals(Category.INBOX)){
			DetachedCriteria cri = DetachedCriteria.forClass(Inbox.class);
			cri.add(Restrictions.eq("id", id));
			cri.add(Restrictions.eq("userId", retriever));
			
			ArrayList<Object> list = HibernateUtil.list(cri, false);
			if(list != null){
				Inbox mail = (Inbox) list.get(0);
				response.setInbox(new ArrayList<Inbox>());
				response.getInbox().add(mail);
				if(mail.getStatus().equals(Status.UNREAD.toString())){
					mail.setStatus(Status.READ.toString());
					HibernateUtil.update(mail, false);
				}
				response.setStatus(true);
			}else{
				response.setStatus(false);
			}
		}else if(category.equals(Category.OUTBOX)){
			DetachedCriteria cri = DetachedCriteria.forClass(Outbox.class);
			cri.add(Restrictions.eq("id", id));
			cri.add(Restrictions.eq("userId", retriever));
			
			ArrayList<Object> list = HibernateUtil.list(cri, false);
			if(list != null){
				Outbox mail = (Outbox) list.get(0);
				response.setOutbox(new ArrayList<Outbox>());
				response.getOutbox().add(mail);
				response.setStatus(true);
			}else{
				response.setStatus(false);
			}
		}else{
			response.setStatus(false);
		}
		
		logger.debug("AntMailService.readMail() ended");
		return response;
	}

}

